import Database from 'better-sqlite3';
import {DataFormatUtils, DbMetadataUtils, TransactionUtils} from '../common';
import {EntityClass} from "../types";

/**
 * 表结构差异
 */
export interface TableDiff {
  /**
   * 需要添加的列
   */
  addedColumns: string[];
  /**
   * 需要修改的列
   */
  alteredColumns: string[];
  /**
   * 需要删除的列
   */
  removedColumns: string[];
  /**
   * 是否需要重建表
   */
  needsRebuild: boolean;
}

/**
 * 数据库迁移工具
 */
export class MigrationUtil {
  /**
   * 检查模型与数据库表的差异
   * @param db 数据库实例
   * @param entityClass 实体类
   * @returns 表差异信息
   */
  public static checkTableDiff(
    db: Database.Database,
    entityClass: EntityClass
  ): TableDiff {
    const tableInfo = entityClass.getTableInfo<any>();
    const tableName = tableInfo.name;

    // 检查表是否存在
    if (!DbMetadataUtils.isTableExists(db, tableName)) {
      // 表不存在，所有列都是新增的
      return {
        addedColumns: Object.keys(tableInfo.columns),
        alteredColumns: [],
        removedColumns: [],
        needsRebuild: false
      };
    }

    // 获取数据库中的列信息
    const dbColumns = DbMetadataUtils.getTableColumns(db, tableName);
    const dbColumnNames = dbColumns.map(col => col.name);

    // 获取模型定义的列名
    const modelColumnNames = Object.keys(dbColumnNames);

    // 找出新增列和删除列
    const addedColumns = modelColumnNames.filter(col => !dbColumnNames.includes(col));
    const removedColumns = dbColumnNames.filter(col => !modelColumnNames.includes(col));

    // 检查列类型变更
    const alteredColumns: string[] = [];
    for (let columnName in tableInfo.columns) {
      const modelCol = tableInfo.columns[columnName];
      const dbCol = dbColumns.find(col => col.name === columnName);
      if (dbCol) {
        // 检查类型变更
        const modelType = modelCol.type.toUpperCase();
        const dbType = dbCol.type.toUpperCase();

        if (modelType !== dbType) {
          alteredColumns.push(columnName);
        }

        // 检查非空约束变更
        const modelNotNull = modelCol.notNull === true;
        const dbNotNull = dbCol.notnull === 1;

        if (modelNotNull !== dbNotNull) {
          if (!alteredColumns.includes(columnName)) {
            alteredColumns.push(columnName);
          }
        }

        // 检查默认值变更
        const modelDefault = modelCol.default;
        const dbDefault = dbCol.dflt_value;

        // 使用工具函数格式化默认值
        const modelDefaultStr = DataFormatUtils.formatDefaultValue(modelDefault);
        const dbDefaultStr = DataFormatUtils.formatDefaultValue(dbDefault);

        if (modelDefaultStr !== dbDefaultStr) {
          if (!alteredColumns.includes(columnName)) {
            alteredColumns.push(columnName);
          }
        }
      }
    }

    // 确定是否需要重建表
    const needsRebuild = removedColumns.length > 0 || alteredColumns.length > 0;

    return {
      addedColumns,
      alteredColumns,
      removedColumns,
      needsRebuild
    };
  }

  /**
   * 迁移表结构以匹配实体模型
   * @param db 数据库实例
   * @param entityClass 实体类
   * @param preserveData 是否保留数据
   * @returns 是否成功
   */
  public static migrateTable(
    db: Database.Database,
    entityClass: EntityClass,
    preserveData: boolean = true
  ): boolean {
    try {
      const tableInfo = entityClass.getTableInfo<any>();
      const tableName = tableInfo.name;

      // 检查表是否存在
      if (!DbMetadataUtils.isTableExists(db, tableName)) {
        // 表不存在，直接创建
        db.exec(entityClass.getCreateTableSQL());
        return true;
      }

      // 检查表差异
      const diff = this.checkTableDiff(db, entityClass);

      // 开始事务
      TransactionUtils.executeTransaction(db, () => {
        // 处理不需要重建的简单更改
        if (!diff.needsRebuild) {
          // 添加新列
          for (const colName of diff.addedColumns) {
            const colInfo = tableInfo.columns[colName];
            if (colInfo) {
              let alterSql = `ALTER TABLE ${tableName} ADD COLUMN ${colName} ${colInfo.type}`;

              if (colInfo.notNull) {
                // SQLite在添加非空列时需要默认值
                const hasDefault = colInfo.default !== undefined;
                if (!hasDefault) {
                  throw new Error(`无法添加没有默认值的非空列: ${colName}`);
                }
                alterSql += ` NOT NULL`;
              }

              if (colInfo.default !== undefined) {
                if (typeof colInfo.default === 'string') {
                  alterSql += ` DEFAULT '${colInfo.default}'`;
                } else {
                  alterSql += ` DEFAULT ${colInfo.default}`;
                }
              }

              db.exec(alterSql);
            }
          }
        } else {
          // 需要重建表的复杂更改
          if (preserveData) {
            this.rebuildTableWithData(db, entityClass);
          } else {
            this.rebuildTable(db, entityClass);
          }
        }
      });

      return true;
    } catch (error) {
      console.error(`迁移表 ${entityClass.getTableInfo().name} 失败:`, error);
      return false;
    }
  }

  /**
   * 重建表（不保留数据）
   * @param db 数据库实例
   * @param entityClass 实体类
   * @returns 是否成功
   */
  public static rebuildTable(
    db: Database.Database,
    entityClass: EntityClass
  ): boolean {
    try {
      const tableInfo = entityClass.getTableInfo();
      const tableName = tableInfo.name;

      // 开始事务
      TransactionUtils.executeTransaction(db, () => {
        // 删除旧表
        db.exec(`DROP TABLE IF EXISTS ${tableName}`);

        // 创建新表
        db.exec(entityClass.getCreateTableSQL());
      });

      return true;
    } catch (error) {
      console.error(`重建表 ${entityClass.getTableInfo().name} 失败:`, error);
      return false;
    }
  }

  /**
   * 重建表并保留数据
   * @param db 数据库实例
   * @param entityClass 实体类
   * @returns 是否成功
   */
  private static rebuildTableWithData(
    db: Database.Database,
    entityClass: EntityClass
  ): boolean {
    try {
      const tableInfo = entityClass.getTableInfo();
      const tableName = tableInfo.name;
      const tempTableName = `${tableName}_temp_migrate`;

      // 获取数据库中当前表的列
      const dbColumns = DbMetadataUtils.getTableColumns(db, tableName);
      const dbColumnNames = dbColumns.map(col => col.name);

      // 获取模型定义的列名
      const modelColumnNames = Object.keys(tableInfo.columns);

      // 找出两者共有的列，用于数据转移
      const commonColumns = dbColumnNames.filter(col => modelColumnNames.includes(col));

      if (commonColumns.length === 0) {
        // 没有共同列，直接重建
        return this.rebuildTable(db, entityClass);
      }

      // 开始事务
      TransactionUtils.executeTransaction(db, () => {
        // 创建新表结构
        db.exec(entityClass.getCreateTableSQL().replace(tableName, tempTableName));

        // 复制数据
        const columnsStr = commonColumns.join(', ');
        db.exec(`INSERT INTO ${tempTableName} (${columnsStr}) SELECT ${columnsStr} FROM ${tableName}`);

        // 删除旧表
        db.exec(`DROP TABLE ${tableName}`);

        // 重命名新表
        db.exec(`ALTER TABLE ${tempTableName} RENAME TO ${tableName}`);
      });

      return true;
    } catch (error) {
      console.error(`带数据重建表 ${entityClass.getTableInfo().name} 失败:`, error);
      return false;
    }
  }
}
